#include "pch.hpp"
#include "Game.hpp"




Game::Game(Engine::IEngine::ptr engine, services::provider::ptr provider)
	: m_engine(engine)

	, m_entitySystem(engine->entitySystem())

	, m_scriptSystem(engine->scriptSystem())
	, m_contextPool(m_scriptSystem->contextPool())
	, m_logicModule(m_scriptSystem->moduleFromFile("unnamed", "../Game/scripts/main.as"))

	, m_logger(provider->service<logger::stream>())
{
	//
	// Debugging
	//

	auto desktop = m_engine->uiSystem()->desktop();
	m_text = Engine::Ui::Text::create("This is an awesome text", desktop);
	m_text->setPos(int2(0, 0));

	m_frame = Engine::Ui::Frame::create(desktop);
	m_frame->setPos(int2(30, 30));
	m_frame->resize(intsize2(100, 100));

	m_window = Engine::Ui::Window::create(desktop);
	m_window->setPos(int2(500, 500));
	m_window->resize(intsize2(100, 100));

	desktop->add(m_text);
	desktop->add(m_frame);
	desktop->add(m_window);


	//
	// Starting the game
	//

	// Initialize the game, ie. call the init() method
	// of the script
	int mainId = m_logicModule->functionIdByDecl("void init(Game@)");
	auto context = m_contextPool->context();
	context->prepare(mainId);
	context->setArgObject(0, this);
	context->execute();

	if(!m_currentGameState)
		throw boostext::programming_error("The init() function is required to set the first GameState: The game must shut down.");
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Game::~Game()
{
	if(m_currentGameState)
		m_currentGameState->deactivated();
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Game::setGameState(asIScriptObject* gameState)
{
	auto gs = Engine::Script::pointer<asIScriptObject>(gameState);
	if(!gs)
		return;

	if(m_currentGameState)
		m_currentGameState->deactivated();

	m_currentGameState = GameState(this, m_contextPool, gs);

	m_currentGameState->activated();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Engine::Entity::System* Game::entitySystem()
{
	return m_entitySystem.get();
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Game::update()
{
	// First, advance the logic
	m_currentGameState->update();

	// Then advance the engine (ie. physics update & rendering)
	m_engine->update();

	// Done :)
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Game::declareType(Engine::Script::System::ptr engine)
{
	engine->registerObjectType("Game", 0, asOBJ_REF);
	engine->registerObjectBehaviour("Game", asBEHAVE_ADDREF, "void f()", asMETHOD(Game, dummy), asCALL_THISCALL);
	engine->registerObjectBehaviour("Game", asBEHAVE_RELEASE, "void f()", asMETHOD(Game, dummy), asCALL_THISCALL);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Game::registerType(Engine::Script::System::ptr engine)
{
	engine->registerObjectMethod("Game", "void setGamestate(GameState@)", asMETHOD(Game, setGameState), asCALL_THISCALL);
	engine->registerObjectMethod("Game", "EntitySystem@ get_entitySystem()", asMETHOD(Game, entitySystem), asCALL_THISCALL);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Game::dummy()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////
